package icantalk.voip;
import java.io.IOException;
import java.math.BigInteger;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;

/**
 * Class used for soundcard IO operations. Implements
 * recording and playing.
 *
 * @author Antonín Brettšnajdr
 */
public class SoundIO {

    private TargetDataLine tdl;
    private SourceDataLine sdl;

    public void setUpMicrophone() throws LineUnavailableException {
        AudioFormat audioFormat = new AudioFormat(8000, 16, 1, true, false);
        DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);

        tdl = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
        tdl.open(audioFormat);

    }

    public void setUpPlayback() throws LineUnavailableException {
        AudioFormat af = new AudioFormat(8000, 16, 1, true, false);
        sdl = AudioSystem.getSourceDataLine(af);
        sdl.open(af);
    }

    public void startRecording() {
        if (tdl != null) {
            tdl.start();
        }
    }

    public void startPlaying() {
        if (sdl != null) {
            sdl.start();
        }
    }

    public void stopPlaying() {
        if (sdl != null) {
        	sdl.close();
            sdl.stop();
        }
    }

    public void stopRecording() {
        if (tdl != null) {
        	tdl.close();
            tdl.stop();
        }
    }

    public int readSamples(byte[] b, int off, int len) throws IOException {
        return tdl.read(b, off, len);
    }

    public int writeSamples(byte[] b, int off, int len) throws IOException {
        return sdl.write(b, off, len);
    }

    public void freeResources() {
        tdl = null;
        sdl = null;
        
        System.gc();
    }

    public static byte[] removeDcOffset(byte[] b) {

        BigInteger bi;
        long sum = 0;
        long[] samples = new long[b.length/2];
        long val = 0;

        byte[] out = new byte[b.length];

        for (int i = 0; i < b.length; i+=2) {
            bi = new BigInteger(new byte[]{b[i+1],b[i]});
            val = bi.longValue();
            samples[i/2] = val;
            sum+= val;
        }

        long offset = sum / b.length;

        //offset + anti clipping algorithm
        for (int i = 0; i < samples.length; i++) {
            samples[i] -= offset;

            val = samples[i];
            if (val > 30000) samples[i] = 30000;
            else if (val < -30000) samples[i] = -30000;
            

        }
        

        return Conversions.LongTo16bitPCMbyte(samples);
        
    }

}
